package kbs.scm
{
    import flash.utils.getDefinitionByName;

    public class PrimitiveFunction extends Primitive
    {
        public function scmapply(alist:AList, env:Env):Base
        { throw new Error("Must override scmapply "+this); }
        public function toObject(b:Base, env:Env):Object
        {
            if (b is ObjectWrapped) {
                return (b as ObjectWrapped).getObject();
            }
            if (b is Num) {
                return (b as Num).getNum();
            }
            if (b is Str) {
                return (b as Str).getStr();
            }
            if (b is NewInstanceFunction) {
                // This becomes just the class instance
                return getDefinitionByName(NewInstanceFunction(b).getName());
            }
            if (b is LambdaFunction) {
                // we wrap an scm function into an anonymous
                // AS function, which evals lambda when called,
                // and then returns the primitive version of
                // the apply'ed expression.

                return function(...rest):* {
                    var al:AList = new AList([]);
                    for (var i:uint=0; i<rest.length; i++) {
                        al.append(toBase(rest[i]));
                    }
                    var evaluator:Eval = env.getEvaluator();
                    var ret:Object =
                        toObject(evaluator.scmapply(b, al, env), env);
                    return ret;
                };
            }

            throw new Error("Sorry -- cannot unpack "+b);
        }
        public function toBase(o:Object):Base
        {
            if (typeof(o) === 'string') {
                return new Str(o.toString());
            }
            else if (typeof(o) === 'number') {
                return new Num(o as int);
            }
            // I'm missing a way to wrap a Function
            // as a LambdaFunction, hmm...
            else {
                return new ObjectWrapped(o);
            }
        }
    }
}
